/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is Forte for Java, Community Edition. The Initial * Developer of the Original Code is Sun Microsystems, Inc. Portions * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved. */ package org.netbeans.modules.apisupport.beanbrowser; import java.beans.*; import java.util.*; import org.openide.*; import org.openide.nodes.*; import org.openide.util.*; /** A list of all properties in a property set. * The keys are of type Node.Property. */ public class PropSetKids extends Children.Keys { private Collection keys; private Node original; private Node.PropertySet ps; private PropertyChangeListener pcListener = null; public PropSetKids (Node original, Node.PropertySet ps) { this.ps = ps; this.original = original; } private void setKeys0 (Collection c) { setKeys (c); keys = c; } /** Update the key list. * Looks for all properties which are readable, and not primitive or String or Class. */ private void updateKeys () { Collection newKeys = new ArrayList (); Node.Property[] props = ps.getProperties (); for (int j = 0; j < props.length; j++) { Node.Property prop = props[j]; if (prop.canRead ()) { Class type = prop.getValueType (); if (! (type.isPrimitive () || type == String.class || type == Class.class)) { newKeys.add (prop); } } } setKeys0 (newKeys); } /** Set the keys. * Also attach a listener to the original node so that if one of its * properties (node properties, not meta-properties of the node itself) * changes, the children can be recalculated. */ protected void addNotify () { updateKeys (); if (pcListener == null) { pcListener = new PropertyChangeListener () { public void propertyChange (PropertyChangeEvent ev) { String prop = ev.getPropertyName (); Iterator it = getKeysIterator (); Object found = null; while (it.hasNext ()) { Object key = it.next (); if (key instanceof Node.Property && ((Node.Property) key).getName ().equals (prop)) { found = key; } } if (found == null) { // Should not happen. updateKeys (); } else { refreshKey0 (found); } } }; original.addPropertyChangeListener (pcListener); } } // Inner class access methods: private void refreshKey0 (Object key) { refreshKey (key); } private Iterator getKeysIterator () { return keys.iterator (); } /** Remove the listener. */ private void doUnListen () { if (pcListener != null) { original.removePropertyChangeListener (pcListener); pcListener = null; } } protected void finalize () throws Exception { doUnListen (); } protected void removeNotify () { doUnListen (); setKeys0 (Collections.EMPTY_SET); } /** Create the node for this property. * @param key the property * @return the (one) node to represent it */ protected Node[] createNodes (Object key) { return new Node[] { makePropertyNode ((Node.Property) key) }; } /** Make a node for a property and its value. * @param prop the property to represent * @return a node to represent it */ private static Node makePropertyNode (Node.Property prop) { Class type = prop.getValueType (); Node node; try { node = makeObjectNode (prop.getValue ()); } catch (Exception e) { node = makeErrorNode (e); } node.setDisplayName (Utilities.getClassName (type) + " " + prop.getDisplayName () + " = " + node.getDisplayName ()); return node; } /** Make a node to meaningfully represent some object. * Special treatment for null; arrays or generalized collections; String and Class objects. * All else gets a RefinedBeanNode. * The name and tooltip are set to something helpful. * @param val the object to represent * @return a node displaying it */ public static Node makeObjectNode (Object val) { if (val == null) { return makePlainNode ("null"); } else if (val instanceof Object[]) { return makeCollectionNode (Collections.enumeration (Arrays.asList ((Object[]) val))); } else if (val.getClass ().isArray ()) { return makeCollectionNode (Collections.enumeration (Arrays.asList (Utilities.toObjectArray (val)))); } else if (val instanceof Enumeration) { return makeCollectionNode ((Enumeration) val); } else if (val instanceof Collection) { return makeCollectionNode (Collections.enumeration ((Collection) val)); } else if (val instanceof String) { return makePlainNode ("\"" + (String) val + "\""); } else if (val instanceof Class) { return makePlainNode ("class " + ((Class) val).getName ()); } else { Node objnode; try { objnode = new RefinedBeanNode (val); } catch (IntrospectionException e) { objnode = makeErrorNode (e); } objnode.setShortDescription ("String value: `" + val + "'; short description: " + objnode.getShortDescription ()); objnode.setDisplayName (objnode.getDisplayName () + " (class " + val.getClass ().getName () + ")"); return Wrapper.make (objnode); } } /** Make a leaf node just displaying some text. * @param name the text * @return the node */ static Node makePlainNode (String name) { AbstractNode toret = new AbstractNode (Children.LEAF) { public HelpCtx getHelpCtx () { return new HelpCtx ("org.netbeans.modules.apisupport.beanbrowser"); } }; toret.setName (name); toret.setIconBase ("/org/netbeans/modules/apisupport/resources/BeanBrowserIcon"); return toret; } /** Make a node representing an error condition and describing the error. * @param t the error * @return a node displaying it (as a Bean) */ static Node makeErrorNode (Throwable t) { Node node = makeObjectNode (t); node.setDisplayName ("[thrown] " + node.getDisplayName ()); return node; } /** Make a node representing an array or list or somesuch. * Safety valve warns the user before creating a huge array. * @param val an Enuemration of Object's * @return a node displaying the objects as children */ private static Node makeCollectionNode (final Enumeration val) { final Node[] _base = new Node[] { null }; final String defaultName = "<list of objects>"; Children kids = new Children.Array () { protected void addNotify () { new Thread (new Runnable () { public void run () { int count = 0; while (val.hasMoreElements ()) { Node n = makeObjectNode (val.nextElement ()); n.setDisplayName ("[" + count + "] " + n.getDisplayName ()); add (new Node[] { n }); if (count++ == 50) { if (! NotifyDescriptor.OK_OPTION.equals ( TopManager.getDefault ().notify (new NotifyDescriptor.Confirmation (new String[] { "There were over 50 elements in this array.", "Actually show all of them?" })))) { break; } } } if (defaultName.equals (_base[0].getDisplayName ())) { _base[0].setDisplayName ("A list of " + count + " children..."); _base[0].setShortDescription (_base[0].getDisplayName ()); } else { _base[0].setShortDescription ("[" + count + " children] " + _base[0].getShortDescription ()); } } }, "making collection node").start (); } }; AbstractNode base = new AbstractNode (kids) { public HelpCtx getHelpCtx () { return new HelpCtx ("org.netbeans.modules.apisupport.beanbrowser"); } }; _base[0] = base; base.setName ("collection"); base.setDisplayName (defaultName); base.setIconBase ("/org/netbeans/modules/apisupport/resources/BeanBrowserIcon"); return base; } } /* * Log * 20 Gandalf-post-FCS1.17.1.1 3/30/00 Jesse Glick Collection nodes now * made only on demand. * 19 Gandalf-post-FCS1.17.1.0 3/9/00 Jesse Glick Minor collection node * bugfix. * 18 Gandalf 1.17 2/4/00 Jesse Glick Clipboard support. * 17 Gandalf 1.16 1/19/00 Jesse Glick Collection node * improvements. * 16 Gandalf 1.15 1/13/00 Jesse Glick FeatureDescriptor bug. * 15 Gandalf 1.14 1/12/00 Jesse Glick Hopefully fixing a * deadlock. * 14 Gandalf 1.13 10/23/99 Ian Formanek NO SEMANTIC CHANGE - Sun * Microsystems Copyright in File Comment * 13 Gandalf 1.12 10/13/99 Jesse Glick Various fixes and * enhancements: - added a Changes.txt - fixed handling of * OpenAPIs.zip on install/uninstall (previously did not correctly unmount * on uninstall, nor check for already-mounted on install) - added a * CompilerTypeTester - display name & icon updates from Tim - * removed link to ToDo.txt from docs page - various BeanInfo's, both * in templates and in the support itself, did not display superclass * BeanInfo correctly - ExecutorTester now permits user to customize * new executor instance before running it * 12 Gandalf 1.11 10/7/99 Jesse Glick Made a method public; * context help. * 11 Gandalf 1.10 10/7/99 Jesse Glick Package change. Also * cloning in Wrapper.make, which may be necessary. * 10 Gandalf 1.9 9/10/99 Jesse Glick Children.Keys.keys * removed. * 9 Gandalf 1.8 6/9/99 Ian Formanek ---- Package Change To * org.openide ---- * 8 Gandalf 1.7 5/27/99 Jesse Glick Clean-up: comments, * licenses, removed debugging code, a few minor code changes. * 7 Gandalf 1.6 5/26/99 Jesse Glick Display child counts of * arrays. * 6 Gandalf 1.5 5/25/99 Jesse Glick Fully cleaned up name * handling, looks much nicer now. Much safer too. * 5 Gandalf 1.4 5/24/99 Jesse Glick Using RefinedBeanNode * for CustomizeBeanAction. * 4 Gandalf 1.3 5/21/99 Jesse Glick Confirmation before * showing huge array. * 3 Gandalf 1.2 5/19/99 Jesse Glick Arrays of primitives * handled, sort of. * 2 Gandalf 1.1 5/19/99 Jesse Glick More useful error node. * 1 Gandalf 1.0 5/18/99 Jesse Glick * $ */